---
title: Stronghold
description: 加密的、安全的数据库。
plugin: stronghold
---

import PluginLinks from '@components/PluginLinks.astro';
import Compatibility from '@components/plugins/Compatibility.astro';

import { Steps, Tabs, TabItem } from '@astrojs/starlight/components';
import CommandTabs from '@components/CommandTabs.astro';

<PluginLinks plugin={frontmatter.plugin} />

使用 [IOTA Stronghold](https://github.com/iotaledger/stronghold.rs) 加密数据库和安全运行时存储秘密和密钥。

## 支持的平台

<Compatibility plugin={frontmatter.plugin} />

## 设置

安装 stronghold 插件开始。

<Tabs>
	<TabItem label="自动" >
		使用项目的包管理器来添加依赖。

    	{ ' ' }

    	<CommandTabs
    		npm="npm run tauri add stronghold"
    		yarn="yarn run tauri add stronghold"
    		pnpm="pnpm tauri add stronghold"
    		bun="bun tauri add stronghold"
    		cargo="cargo tauri add stronghold"
    	/>
    </TabItem>

    <TabItem label = "手动">
    	<Steps>

    	1. 在你的 `Cargo.toml` 文件中添加以下内容来安装 stronghold 插件。

    		```toml title="src-tauri/Cargo.toml"
    		[dependencies]
    		tauri-plugin-stronghold = "2.0.0"
    		# 或者使用 Git：
    		tauri-plugin-stronghold = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
    		```

    	2. 修改 `lib.rs` 来初始化插件。

    		```rust title="src-tauri/src/lib.rs" ins={3}
    		fn run() {
    				tauri::Builder::default()
    						.plugin(tauri_plugin_stronghold::Builder::new(|password| {}).build())
    						.run(tauri::generate_context!())
    						.expect("error while running tauri application");
    		}
    		```

    	3. 使用你喜欢的 JavaScript 包管理器安装 JavaScript Guest 绑定。

    		<CommandTabs
    			npm="npm install @tauri-apps/plugin-stronghold"
    			yarn="yarn add @tauri-apps/plugin-stronghold"
    			pnpm="pnpm add @tauri-apps/plugin-stronghold"
    			bun="bun add @tauri-apps/plugin-stronghold"
    		/>

    	</Steps>
    </TabItem>

</Tabs>

## 用法

### 使用自定义密码散列函数初始化

```rust title="src-tauri/src/lib.rs"
pub fn run() {
		tauri::Builder::default()
				.plugin(
						tauri_plugin_stronghold::Builder::new(|password| {
								// 在这里使用 argon2、blake2b 或任何其他安全算法对密码进行散列。
								// 下面是一个使用 `rust-argon2` 板条箱对密码进行散列的示例实现：
								use argon2::{hash_raw, Config, Variant, Version};

								let config = Config {
										lanes: 4,
										mem_cost: 10_000,
										time_cost: 10,
										variant: Variant::Argon2id,
										version: Version::Version13,
										..Default::default()
								};
								let salt = "your-salt".as_bytes();
								let key =
										hash_raw(password.as_ref(), salt, &config).expect("failed to hash password");

								key.to_vec()
						})
						.build(),
				)
				.run(tauri::generate_context!())
				.expect("error while running tauri application");
}
```

### 使用 argon2 密码散列函数初始化

```rust title="src-tauri/src/lib.rs"
use tauri::Manager;

pub fn run() {
		tauri::Builder::default()
				.setup(|app| {
						let salt_path = app
								.path()
								.app_local_data_dir()
								.expect("could not resolve app local data path")
								.join("salt.txt");
						app.handle().plugin(tauri_plugin_stronghold::Builder::with_argon2(&salt_path).build())?;
						Ok(())
				})
				.run(tauri::generate_context!())
				.expect("error while running tauri application");
}
```

### 在 JavaScript 使用

Stronghold 插件可以在 JavaScript 中使用。

```javascript
import { Client, Stronghold } from '@tauri-apps/plugin-stronghold';
import { appDataDir } from '@tauri-apps/api/path';

const initStronghold = async () => {
	const vaultPath = `${await appDataDir()}/vault.hold`;
	const vaultPassword = 'vault password';
	const stronghold = await Stronghold.load(vaultPath, vaultPassword);

	let client: Client;
	const clientName = 'name your client';
	try {
		client = await stronghold.loadClient(clientName);
	} catch {
		client = await stronghold.createClient(clientName);
	}

	return {
		stronghold,
		client,
	};
};

// 向 store 中插入一条记录
async function insertRecord(store: any, key: string, value: string) {
	const data = Array.from(new TextEncoder().encode(value));
	await store.insert(key, data);
}

// 从 store 中读取一条记录
async function getRecord(store: any, key: string): Promise<string> {
	const data = await store.get(key);
	return new TextDecoder().decode(new Uint8Array(data));
}

const { stronghold, client } = await initStronghold();

const store = client.getStore();
const key = 'my_key';

// 向 store 中插入一条记录
insertRecord(store, key, 'secret value');

// 从 store 中读取一条记录
const value = await getRecord(store, key);
console.log(value); // 'secret value'

// 保存更新
await stronghold.save();

// 从 store 中删除一条记录
await store.remove(key);
```

## 权限

默认情况下，所有插件命令都被阻止，无法访问。你必须在你的 `capabilities` 配置中定义一个权限列表。

更多信息请参见[访问控制列表](/zh-cn/reference/acl/)。

```json title="src-tauri/capabilities/default.json" ins={8-14}
{
	"$schema": "../gen/schemas/desktop-schema.json",
	"identifier": "main-capability",
	"description": "Capability for the main window",
	"windows": ["main"],
	"permissions": [
		"path:default",
		"stronghold:allow-initialize",
		"stronghold:allow-create-client",
		"stronghold:allow-load-client",
		"stronghold:allow-save",
		"stronghold:allow-save-store-record"
		"stronghold:allow-get-store-record",
		"stronghold:allow-remove-store-record",
	]
}
```

| 权限                                   | 描述                                                          |
| -------------------------------------- | ------------------------------------------------------------- |
| `stronghold:allow-create-client`       | 在没有预先配置的作用域的情况下启用 create_client 命令。       |
| `stronghold:deny-create-client`        | 拒绝没有任何预配置范围的 create_client 命令。                 |
| `stronghold:allow-destroy`             | 在没有预先配置的作用域的情况下启用 destroy 命令。             |
| `stronghold:deny-destroy`              | 拒绝没有任何预配置范围的 destroy 命令。                       |
| `stronghold:allow-execute-procedure`   | 在没有预先配置的作用域的情况下启用 execute_procedure 命令。   |
| `stronghold:deny-execute-procedure`    | 拒绝没有任何预配置范围的 execute_procedure 命令。             |
| `stronghold:allow-get-store-record`    | 在没有预先配置的作用域的情况下启用 get_store_record 命令。    |
| `stronghold:deny-get-store-record`     | 拒绝没有任何预配置范围的 get_store_record 命令。              |
| `stronghold:allow-initialize`          | 在没有预先配置的作用域的情况下启用 initialize 命令。          |
| `stronghold:deny-initialize`           | 拒绝没有任何预配置范围的 initialize 命令。                    |
| `stronghold:allow-load-client`         | 在没有预先配置的作用域的情况下启用 load_client 命令。         |
| `stronghold:deny-load-client`          | 拒绝没有任何预配置范围的 load_client 命令。                   |
| `stronghold:allow-remove-secret`       | 在没有预先配置的作用域的情况下启用 remove_secret 命令。       |
| `stronghold:deny-remove-secret`        | 拒绝没有任何预配置范围的 remove_secret 命令。                 |
| `stronghold:allow-remove-store-record` | 在没有预先配置的作用域的情况下启用 remove_store_record 命令。 |
| `stronghold:deny-remove-store-record`  | 拒绝没有任何预配置范围的 remove_store_record 命令。           |
| `stronghold:allow-save`                | 在没有预先配置的作用域的情况下启用 save 命令。                |
| `stronghold:deny-save`                 | 拒绝没有任何预配置范围的 save 命令。                          |
| `stronghold:allow-save-secret`         | 在没有预先配置的作用域的情况下启用 save_secret 命令。         |
| `stronghold:deny-save-secret`          | 拒绝没有任何预配置范围的 save_secret 命令。                   |
| `stronghold:allow-save-store-record`   | 在没有预先配置的作用域的情况下启用 save_store_record 命令。   |
| `stronghold:deny-save-store-record`    | 拒绝没有任何预配置范围的 save_store_record 命令。             |
